package Tracing;

import prefuse.data.Table;
import prefuse.data.Tuple;
import net.sourceforge.jeval.EvaluationException;
import net.sourceforge.jeval.Evaluator;

public class State extends Table {

	public State(){
		super();
		addColumn("variable", String.class);
		addColumn("value", String.class);
		
	}
	
	public Evaluator assign(){
		
	    Evaluator evaluator = new Evaluator();
		
		for(int i = 0; i < getRowCount(); i++){
			/*
			 * Set the variables.
			 */
			evaluator.putVariable(getString(i, "variable"), getString(i, "value"));

		}
		
		return evaluator;
		
	}
	
	/*
	public boolean Bexecute(String Bexp){
		
		Boolean result = true;
		
		Evaluator evaluator = assign();
		
		String bool;
		try {
			bool = evaluator.evaluate(Bexp);
			if(bool.equals("0.0")){
				result = false;
			}
		} catch (EvaluationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
		
	}
	*/
	
	public String execute(String exp){
		
		return execute(exp, null);
	}
	
	public String execute(String exp, String keepVariable){
		
		String result = null;
		
		Evaluator evaluator = assign();
		
		//change the var in exp into #{} for execution
		
		for(int i = 0 ; i < this.getRowCount(); i++){
			
			String var = this.getString(i, "variable");
			exp = exp.replaceAll(var, "#{"+var+"}");
		}
		
		//System.out.println("exp: " + exp);
		
		try {
			result = evaluator.evaluate(exp);
		} catch (EvaluationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return result;
	}
	
	public String replaceExcept(String exp, String k){
		
		String result = exp;
		for(int i = 0 ; i < this.getRowCount(); i++){
			
			String var = this.getString(i, "variable");
			String val = this.getString(i, "value");
			if(!var.equals(k)){
				result = result.replaceAll(var, val);
			}
		}
		return result;
	}
	
	public String getValue(String exp){
		String result = null;
		for(int i = 0 ; i < this.getRowCount(); i++){
			String var = this.getString(i, "variable");
			String val = this.getString(i, "value");
			if(var.equals(exp)){
				result = val;
				break;
			}
		}
		
		return result;
	}
	
	public void transform(String variable, String exp){
		
		boolean flag = true;
		
		String value = this.execute(exp);
		
		for(int i = 0; i<this.getRowCount(); i++){
			if(this.getString(i, "variable").equals(variable)){
				flag = false;
				this.setString(i, "value", value);
				break;
			}
		}
		
		//This is no such a variable in the current state
		if(flag == true){
			this.addRow();
			int rowCount = this.getRowCount();
			this.setString(rowCount-1, "variable", variable);
			this.setString(rowCount-1,"value",value);
		}
		
		
	}
	
	public void set(String variable, String value){
		
		boolean flag = true;
		
		for(int i = 0; i<this.getRowCount(); i++){
			if(this.getString(i, "variable").equals(variable)){
				flag = false;
				this.setString(i, "value", value);
				break;
			}
		}
		
		//This is no such a variable in the current state
		if(flag == true){
			this.addRow();
			int rowCount = this.getRowCount();
			this.setString(rowCount-1, "variable", variable);
			this.setString(rowCount-1,"value",value);
		}
		
		
	}
	
	
	public String toString(){
		//System.out.println(getRowCount());
		//System.out.println("variable------value");
		StringBuffer buf = new StringBuffer();
		if(getRowCount()>0){
			buf.append("(");
			for(int i = 0; i < getRowCount(); i++){
				buf.append(getString(i, "variable")+"\u21A6"+getString(i, "value")+", ");
			}	
			buf.replace(buf.lastIndexOf(", "), buf.length(), ")");
		}else{
			buf.append("(" + UI.Constants.empty + ")");
		}
        return buf.toString();
	}
	
	public void print(){
		System.out.println(this.toString());
	}

	public State copy(){
		State copy = new State();
		for(int i = 0; i < getRowCount(); i++){
			copy.addRow();
			copy.setString(i, "variable", this.getString(i, "variable"));
			copy.setString(i, "value", this.getString(i, "value"));
		}
		
		return copy;
	}
	
	public Tuple compareWith(State Estate){
		Tuple result = null;
		if(Estate!=null){
			for(int i = 0; i < Estate.getRowCount(); i++){
				for(int j = 0; j < this.getRowCount(); j++){
					if(Estate.getString(i, "variable").equals(this.getString(j, "variable"))){
						if(Float.valueOf(Estate.getString(i, "value"))-Float.valueOf(this.getString(j, "value"))!=0){
							result = Estate.getTuple(i);
							return result;
						}
					}
				}
			}
		}
		
		return result;
	}
	
}
